package util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Random;

/**
 * 短信验证码工具类
 * @author dqy
 */
public class SMSUtils {

    /**
     * The constant CHECK_RESULT_TRUE.
     */
    public static final int CHECK_RESULT_TRUE = 1;//表示验证成功
    /**
     * The constant CHECK_RESULT_FALSE.
     */
    public static final int CHECK_RESULT_FALSE = 2;//表示验证失败
    /**
     * The constant CHECK_RESULT_INVALID.
     */
    public static final int CHECK_RESULT_INVALID = 3;//表示验证码失效，需要重新发送
    private static final Logger logger = LogManager.getLogger(SMSUtils.class);
    private static final String SESSION_KEY_SMS_CODE = "sessionKeySMSCode";//表示短信验证码
    private static final String SESSION_KEY_SMS_PHONE = "sessionKeySMSPhone";//表示短信收件人
    private static final String SESSION_KEY_SMS_TIME = "sessionKeySMSTime";//表示短信发送时间
    private static final String SESSION_KEY_SMS_REMAIN_CHECK_COUNT = "sessionKeySMSRemainCheckCount";//表示剩余验证次数

    /**
     * Check sms code int.
     *
     * @param request     the request
     * @param response    the response
     * @param phone       the phone
     * @param requestCode the request code
     * @return the int
     */
    public static int checkSMSCode(HttpServletRequest request, HttpServletResponse response, String phone, String requestCode) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length < 4) {
            return CHECK_RESULT_FALSE;
        }
        Cookie phoneCookie = null;
        Cookie sendTimeCookie = null;
        Cookie codeCookie = null;
        Cookie remainCountCookie = null;
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            if (SESSION_KEY_SMS_PHONE.equals(name)) {
                phoneCookie = cookie;
            } else if (SESSION_KEY_SMS_TIME.equals(name)) {
                sendTimeCookie = cookie;
            } else if (SESSION_KEY_SMS_CODE.equals(name)) {
                codeCookie = cookie;
            } else if (SESSION_KEY_SMS_REMAIN_CHECK_COUNT.equals(name)) {
                remainCountCookie = cookie;
            }
        }
        if (phoneCookie == null || sendTimeCookie == null || codeCookie == null || remainCountCookie == null) {
            return CHECK_RESULT_FALSE;
        }
        String cP = phoneCookie.getValue();
        String cC = codeCookie.getValue();
        Long cST;
        Integer cRCC;
        try {
            cST = Long.valueOf(sendTimeCookie.getValue());
            cRCC = Integer.valueOf(remainCountCookie.getValue());
        } catch (NumberFormatException e) {
            return CHECK_RESULT_FALSE;
        }
        if (phone == null || requestCode == null) {
            logger.debug("检查短信验证码失败，phone{}，requestCode：{}", phone, requestCode);
            return CHECK_RESULT_FALSE;
        }
        if (!phone.equals(cP)) {
            logger.debug("检查短信验证码失败，phone{}，requestCode：{}，sessionPhone：{}", phone, requestCode, cP);
            return CHECK_RESULT_FALSE;
        }
        //验证码过期失效
        if (cST - System.currentTimeMillis() > 1000 * 60 * 30) {
            logger.debug("检查短信验证码失败，验证码过期，phone：{}，requestCode：{}", phone, requestCode);
            return CHECK_RESULT_INVALID;
        }

        //如果验证码不匹配

        if (!requestCode.equalsIgnoreCase(cC)) {

            cRCC--;
            //没有剩余验证次数了
            if (cRCC <= 0) {
                codeCookie.setMaxAge(0);
                remainCountCookie.setMaxAge(0);
                sendTimeCookie.setMaxAge(0);
                phoneCookie.setMaxAge(0);
                logger.debug("检查短信验证码失败，验证码错误，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone,
                    requestCode, cC, cRCC);
                setCookies(response, codeCookie, phoneCookie, sendTimeCookie, remainCountCookie);
                return CHECK_RESULT_INVALID;
            } else {
                remainCountCookie = new Cookie(SESSION_KEY_SMS_REMAIN_CHECK_COUNT, String.valueOf(cRCC));
                logger.debug("检查短信验证码失败，验证码错误，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone,
                    requestCode, cC, cRCC);
                setCookies(response, codeCookie, phoneCookie, sendTimeCookie, remainCountCookie);
                return CHECK_RESULT_FALSE;
            }
        }

        //验证码匹配
        codeCookie.setMaxAge(0);
        remainCountCookie.setMaxAge(0);
        sendTimeCookie.setMaxAge(0);
        phoneCookie.setMaxAge(0);
        setCookies(response, codeCookie, phoneCookie, sendTimeCookie, remainCountCookie);
        logger.debug("检查短信验证码成功，phone：{}，requestCode：{}，sessionCode：{}，remainCount：{}", phone, requestCode, cC,
            cRCC);
        return CHECK_RESULT_TRUE;
    }

    /**
     * Send sms code.
     *
     * @param request  the request
     * @param response the response
     * @param url      the url
     * @param username the username
     * @param appKey   the app key
     * @param template the template
     * @param phone    the phone
     */
    public static void sendSMSCode(HttpServletRequest request, HttpServletResponse response, String url, String
        username, String appKey, String template, String phone) {
        // 得到一个随机的5位数字的验证码
        String smsCode = new Random().nextInt(90000) + 10000 + "";
        StringBuilder builder = new StringBuilder();
        builder.append(url).append("?userName=").append(username);
        builder.append("&appKey=").append(appKey);
        builder.append("&templateId=").append(template);
        builder.append("&code=").append(smsCode);
        builder.append("&phoneNum=").append(phone);

        try {
            String result = HttpUtils.get(builder.toString());
            SMSResult smsResult = JsonUtils.toBean(result, SMSResult.class);
            if (smsResult.getCode() == 0) {
                Cookie codeCookie = new Cookie(SESSION_KEY_SMS_CODE, smsCode);
                Cookie phoneCookie = new Cookie(SESSION_KEY_SMS_PHONE, phone);
                Cookie timeCookie = new Cookie(SESSION_KEY_SMS_TIME, String.valueOf(System.currentTimeMillis()));
                Cookie countCookie = new Cookie(SESSION_KEY_SMS_REMAIN_CHECK_COUNT, String.valueOf(5));
                setCookies(response, codeCookie, phoneCookie, timeCookie, countCookie);
                logger.debug("发送短信验证码成功，phone：{}，code：{}", phone, smsCode);
            } else {
                throw new RuntimeException("发送短信验证码失败，发送结果为：" + result);
            }
        } catch (Exception e) {
            logger.debug("发送短信验证码失败，phone：{}，code：{}", phone, smsCode, e);
            throw new RuntimeException("发送短信验证码失败", e);
        }
    }

    private static void setCookies(HttpServletResponse response, Cookie... cookies) {
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                cookie.setMaxAge(300);
                response.addCookie(cookie);
            }
        }
    }

    @SuppressWarnings("unused")
    private static class SMSResult {
        private int code;
        private String msg;

        /**
         * Gets code.
         *
         * @return the code
         */
        public int getCode() {
            return code;
        }

        /**
         * Sets code.
         *
         * @param code the code
         */
        public void setCode(int code) {
            this.code = code;
        }

        /**
         * Gets msg.
         *
         * @return the msg
         */
        public String getMsg() {
            return msg;
        }

        /**
         * Sets msg.
         *
         * @param msg the msg
         */
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
}
